#include "ModbusPoll.h"

#include "modbus-rtu.h"

#include <QJsonDocument>
#include <QJsonObject>
#include <QFile>

ModbusPoll::ModbusPoll()
{
	connectType_ = tcp;
}

bool ModbusPoll::connect()
{
	isConnected_ = false;
	auto settings = &modbusSettings_;
	if (connectType_ == serial)
	{
		isConnected_ = connectDeviceSerial(settings->serialName.toStdString().c_str(),
			settings->baud, settings->parity,
			settings->dataBit, settings->stopBit);
	}
	else if (connectType_ == tcp)
	{
		isConnected_ = connectDeviceTcp(settings->addressIP.toStdString().c_str(), settings->tcpPort);
	}

	return isConnected_;
}

bool ModbusPoll::connectDeviceSerial(const char* deviceName, int baud, char parity, int dataBit, int stopBit)
{
	disconnectDevice();

	modbusDevice_ = modbus_new_rtu(deviceName, baud, parity, dataBit, stopBit);
	modbus_set_slave(modbusDevice_, modbusSettings_.slaveId);
	bool connected = modbus_connect(modbusDevice_) != -1;

	return connected;
}

bool ModbusPoll::connectDeviceTcp(const char* ip, int port)
{
	// 删除旧资源
	disconnectDevice();
	// 1.创建tcp/ip modbus
	modbusDevice_ = modbus_new_tcp(ip, port);
	// 2. 设置超时（关键步骤）
	// 2.1 响应超时：3秒（3000ms）
	if (modbus_set_response_timeout(modbusDevice_, 3, 0) != 0) {
		modbus_free(modbusDevice_);
		return -1;
	}

	// 2.2 字节间超时：500毫秒（防止数据传输中断）
	if (modbus_set_byte_timeout(modbusDevice_, 0, 500000) != 0) {  // 500,000微秒 = 500ms
		modbus_free(modbusDevice_);
		return -1;
	}
	// 3.设置参数，并连接
	modbus_set_slave(modbusDevice_, modbusSettings_.slaveId);
	bool connected = modbus_connect(modbusDevice_) != -1;
	
	return connected;
}

void ModbusPoll::disconnectDevice()
{
	if (modbusDevice_)
	{
		modbus_close(modbusDevice_);
		modbus_free(modbusDevice_);
		modbusDevice_ = nullptr;
	}
}

int ModbusPoll::readCoils(uint8_t* data, int addr, int num)
{
	return modbus_read_bits(modbusDevice_, addr, num, data);
}

int ModbusPoll::writeCoil(uint8_t data, int address)
{
	return modbus_write_bits(modbusDevice_, address, 1, &data);
}

int ModbusPoll::writeCoils(uint8_t* data, int address, int num)
{
	return modbus_write_bits(modbusDevice_, address, num, data);
}

int ModbusPoll::readRegister(uint16_t* data, int address)
{
	int ret = modbus_read_registers(modbusDevice_, address, 1, data);
	//Sleep(3);
	return ret;
}

int ModbusPoll::readRegisters(uint16_t* data, int address, int num)
{
	int ret = modbus_read_registers(modbusDevice_, address, num, data);
	//Sleep(5);
	return ret;
}

int ModbusPoll::writeRegister(uint16_t data, int address)
{
	int ret = modbus_write_register(modbusDevice_, address, data);
	//Sleep(3);
	return ret;
}

int ModbusPoll::writeRegisters(uint16_t* data, int startAddress, int num)
{
	int ret = modbus_write_registers(modbusDevice_, startAddress, num, data);
	//Sleep(5);
	return ret;
}

bool ModbusPoll::read(const char* modbus)
{
	QFile file(modbus);

	QJsonObject root;
	QJsonObject modbusSet;
	if (file.open(QIODevice::ReadOnly))
	{
		auto jsonData = file.readAll();
		file.close();
		QJsonParseError error;
		QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &error);
		if (error.error == QJsonParseError::NoError)
		{
			if (jsonDoc.isObject())
			{
				auto obj = jsonDoc.object();
				auto connectType = obj["connect_type"].toString();
				if (connectType == "serial")
				{
					setConnectType(serial);
				}
				else if (connectType == "tcp")
				{
					setConnectType(tcp);
				}

				int slaveId = obj["slave_id"].toInt();
				modbusSettings_.slaveId = slaveId;
				//modbus_set_slave(modbusDevice_, slaveId);

				if (getConnectType() == serial)
				{
					auto modbusSet = obj["serial"].toObject();
					modbusSettings_.serialName = modbusSet["device_name"].toString();
					modbusSettings_.baud = modbusSet["baud_rate"].toInt();
					modbusSettings_.parity = char(modbusSet["parity"].toInt());
					modbusSettings_.dataBit = modbusSet["data_bit"].toInt();
					modbusSettings_.stopBit =  modbusSet["stop_bit"].toInt();					
				}
				else if (getConnectType() == tcp)
				{
					auto modbusSet = obj["tcp"].toObject();
					
					modbusSettings_.addressIP = modbusSet["ip_address"].toString();
					modbusSettings_.tcpPort = modbusSet["net_port"].toInt();
				}
				else
				{
					qInfo() << "不支持";
					return false;
				}
			}
		}
		else
		{
			return false;
		}
	}
	else
	{
		qInfo() << "读取文件失败：" << modbus;
		return false;
	}

	// 根据读取的配置文件创建modbus设备
	/*if (modbusDevice_ == nullptr)
	{
		switch (getConnectType())
		{
		case tcp:
			modbusDevice_ = modbus_new_tcp(modbusSettings_.addressIP.toStdString().c_str(), modbusSettings_.tcpPort);
			break;
		case serial:
			modbusDevice_ = modbus_new_rtu(modbusSettings_.serialName.toStdString().c_str(),
				modbusSettings_.baud, modbusSettings_.parity, modbusSettings_.dataBit, modbusSettings_.stopBit);
			break;
		}
	}*/

	return true;
}

bool ModbusPoll::write(const char* modbus)
{
	QFile file(modbus);

	QJsonObject root;
	QJsonObject modbusSet;
	root["slave_id"] = modbus_get_slave(modbusDevice_);
	if (getConnectType() == serial)
	{
		modbusSet["device_name"] = modbusSettings_.serialName;
		modbusSet["baud_rate"] = modbusSettings_.baud;
		modbusSet["parity"] = modbusSettings_.parity;
		modbusSet["data_bit"] = modbusSettings_.dataBit;
		modbusSet["stop_bit"] = modbusSettings_.stopBit;
		root["connect_type"] = "serial";
		root["serial"] = modbusSet;
	}
	else if (getConnectType() == tcp)
	{
		modbusSet["ip_address"] = modbusSettings_.addressIP;
		modbusSet["net_port"] = modbusSettings_.tcpPort;
		root["connect_type"] = "tcp";
		root["tcp"] = modbusSet;		
	}
	else
	{
		qInfo() << "不支持";
		return false;
	}
	
	QJsonDocument doc(root);
	if (file.open(QIODevice::WriteOnly))
	{
		file.write(doc.toJson());
	}
	file.close();
	return true;
}
